#include "Shader.h"
#include "Vector3.h"
#include "RayTracer.h"
#include "trax.hpp"

namespace AtomTrace
{  
    const Color shade(const Ray & iRay, HitRecord & hRec, const Scene & scene)
    {
        //const Vector3 & N = hRec.N;
        const Vector3 & N = hRec.GetTriangleNormal();
        //hRec.N = N;
        Color res(0.0f, 0.0f, 0.0f);

        int matAddr = scene.startMatAddr + hRec.matID * 25;

        Color diffuse;
        hRec.matIllum = loadi(matAddr, 0);
        if(hRec.matIllum >= 6)
        	hRec.transIndex = loadf(matAddr, 16);
        if(hRec.matIllum == 3 || hRec.matIllum == 6)
        {
        	//res.Set(1.0f, 1.0f, 1.0f);
        	return res;
        }
        diffuse.LoadFromGM(matAddr+4);

        Vector3 V = hRec.incDir * -1.0f;
        float nDotV = N.Dot(V);
        if(nDotV < 0.0f) hRec.hitFront = false;

        // ambient light
        res += diffuse*scene.lambient*scene.ka;

        int lightSize = 3;
        for(int lightID = 0; lightID<scene.numLights; lightID++)
        {
            PointLight pl;
            pl.LoadFromGM(scene.startLightAddr + lightID * lightSize);
            Vector3 L = pl.GetDirection(hRec.P);

            // <Shadow check> --------------------------------
            float dst = (pl.pos - hRec.P).Length();
            Ray shadow = RayTracer::CastRay(hRec.P, L);
            //Ray shadow = RayTracer::CastRay(hRec.P, pl.pos-hRec.P);

            HitRecord shadowHit;
            shadowHit.Init();
            //shadowHit.t = dst;
            //bool isHit = RayTracer::TraceRay(shadow, scene, shadowHit);
            bool isHit = RayTracer::TraceBVH(shadow, shadowHit);
            if(shadowHit.t < dst) continue;
            // ----------------------------</Shadow check>*/

            Color I = pl.intensity;
            I.Clamp(0.0f, 1.0f);
            /**
            float nDotL = N.Dot(L);
            float cosT;// = max(nDotL, 0.0f);
            //cosT = (N.Dot(L));
            //if(cosT < 0.0f) cosT = -cosT;
            if(nDotL * nDotV < 0.0f) cosT = 0.0f;
            else cosT = max(nDotL, -nDotL);
             **/
            
            //res += diffuse*I*cosT * scene.kd; // only diffuse lighting
            res += PhongDiffuseShade(V, N, L, I, diffuse);
            //res += diffuse*I*cosT;
        }


        return res;
    }
    
    Color PhongDiffuseShade(const Vector3 & V, const Vector3 & N, const Vector3 & L, const Color & I, const Color & diffuse)
    {
        float nDotL = N.Dot(L);
        float nDotV = N.Dot(V);
        
        float cosT;
        if(nDotL * nDotV < 0.0f) cosT = 0.0f;
        else cosT = max(nDotL, -nDotL);
        return (diffuse*I*cosT);
    }
} // namespace AtomTrace
